﻿using BDRUtils.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace BDRUtils.Cached
{
    /// <summary>
    /// redis实现类
    /// </summary>
    public class RedisProvider : ICached
    {
        private readonly RedisHelperBase redisHelperBase;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="redisHelperBase"></param>
        public RedisProvider(RedisHelperBase redisHelperBase)
        {
            this.redisHelperBase = redisHelperBase;
        }

        /// <summary>
        /// 验证缓存项是否存在
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <returns></returns>
        public bool Exists(string key)
        {
            if (key == null)
                throw new ArgumentNullException(nameof(key));
            return redisHelperBase.GetKeys(key).Count() == 1;
        }

        /// <summary>
        /// 清理所有缓存数据
        /// </summary>
        public void Clear()
        {
            redisHelperBase.Clear();
        }

        /// <summary>
        /// 获取缓存对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public T Get<T>(string key)
        {
            string jsonStr = redisHelperBase.GetValue(key);
            if (string.IsNullOrEmpty(jsonStr))
                return default(T);

            return jsonStr.ToObject<T>();
        }

        /// <summary>
        /// 获取缓存对象，不存在时执行funcSet设置
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="funcSet">缓存不存在时要设置缓存的函数</param>
        /// <param name="expiresIn"></param>
        /// <param name="isSliding"></param>
        /// <returns></returns>
        public T GetOrSet<T>(string key, Func<T> funcSet, TimeSpan expiresIn, bool isSliding = false)
        {
            var cache = Get<T>(key);
            if (cache != null)
            {
                return cache;
            }

            var setData = funcSet();
            Set(key, setData, expiresIn, isSliding);
            return setData;
        }

        /// <summary>
        /// 移出
        /// </summary>
        /// <param name="key"></param>
        public void Remove(string key)
        {
            redisHelperBase.DeleteKey(key);
        }

        /// <summary>
        /// 搜索 匹配到的缓存
        /// </summary>
        /// <param name="pattern"></param>
        /// <returns></returns>
        public IList<string> SearchByRegex(string pattern)
        {
            var cacheKeys = redisHelperBase.GetKeys();
            var keys = cacheKeys.Where(k => Regex.IsMatch(k, pattern)).Select(p => p.ToString()).ToList();
            return keys;
        }

        /// <summary>
        /// 删除匹配到的缓存
        /// </summary>
        /// <param name="pattern"></param>
        public void RemoveByRegex(string pattern)
        {
            IList<string> l = SearchByRegex(pattern);
            foreach (var s in l)
            {
                Remove(s);
            };
        }

        /// <summary>
        /// 添加缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="expiresSliding"></param>
        /// <param name="expiressAbsoulte"></param>
        /// <returns></returns>
        public bool Set<T>(string key, T value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte)
        {
            if (key == null)
                throw new ArgumentNullException(nameof(key));
            if (value == null)
                throw new ArgumentNullException(nameof(value));

            redisHelperBase.SetValue(key, value.ToJsonStr(), expiresSliding);

            return Exists(key);
        }

        /// <summary>
        /// 添加缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="expiresIn"></param>
        /// <param name="isSliding"></param>
        /// <returns></returns>
        public bool Set<T>(string key, T value, TimeSpan expiresIn, bool isSliding = false)
        {
            if (key == null)
                throw new ArgumentNullException(nameof(key));
            if (value == null)
                throw new ArgumentNullException(nameof(value));

            redisHelperBase.SetValue(key, value.ToJsonStr(), expiresIn);
            return Exists(key);
        }
    }
}
